<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>8.依赖注入的引导过程 | 被删的前端游乐场</title>
    <meta name="generator" content="VuePress 1.8.2">
    
    <meta name="description" content="Just playing around">
    
    <link rel="preload" href="/front-end-playground/assets/css/0.styles.6ad2a9ca.css" as="style"><link rel="preload" href="/front-end-playground/assets/js/app.1e2670bf.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/2.38d016d1.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/3.e3f029cb.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/106.890f6d8d.js" as="script">
    <link rel="stylesheet" href="/front-end-playground/assets/css/0.styles.6ad2a9ca.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/front-end-playground/" class="home-link router-link-active"><!----> <span class="site-name">被删的前端游乐场</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link">前端领域</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link router-link-active">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/front-end-work/" class="nav-link">前端与工作</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link">前端领域</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link router-link-active">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/front-end-work/" class="nav-link">前端与工作</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-2b653b36><span class="stand" data-v-2b653b36></span> <div class="cat" data-v-2b653b36><div class="body" data-v-2b653b36></div> <div class="head" data-v-2b653b36><div class="ear" data-v-2b653b36></div> <div class="ear" data-v-2b653b36></div></div> <div class="face" data-v-2b653b36><div class="nose" data-v-2b653b36></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div></div> <div class="tail-container" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>Angular框架解读</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-0-prestart.html" class="sidebar-link">0.预热篇</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-metadata.html" class="sidebar-link">1.元数据和装饰器</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-dom-define.html" class="sidebar-link">2.视图抽象定义</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-zonejs.html" class="sidebar-link">3.Zone区域之zone.js</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-zone-ngzone.html" class="sidebar-link">4.Zone区域之ngZone</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-module.html" class="sidebar-link">5.模块化组织</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-1-basic-concepts.html" class="sidebar-link">6.依赖注入的基本概念</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-2-hierarchical-di.html" class="sidebar-link">7.多级依赖注入设计</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-3-bootstrap.html" aria-current="page" class="active sidebar-link">8.依赖注入的引导过程</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-3-bootstrap.html#引导根模块" class="sidebar-link">引导根模块</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-3-bootstrap.html#引导-angular-应用程序" class="sidebar-link">引导 Angular 应用程序</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-3-bootstrap.html#总结" class="sidebar-link">总结</a></li></ul></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-0-design.html" class="sidebar-link">9.Ivy编译器整体设计</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-1-view-data-and-node-injector.html" class="sidebar-link">10.Ivy编译器的视图数据和依赖解析</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>玩转 Angular</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>试试 Cycle.js</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>D3.js 和 Tree</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>试试 Three.js</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>BOX2D.js 文档与教程</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><p>作为“为大型前端项目”而设计的前端框架，Angular 其实有许多值得参考和学习的设计，本系列主要用于研究这些设计和功能的实现原理。本文主要围绕 Angular 中的最大特点——依赖注入，介绍 Angular 依赖注入在体系在应用引导过程中的的设计和实现。</p> <p><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-2-hierarchical-di.html">多级依赖注入</a>中，介绍了模块注入器和元素注入器两种层次结构的注入器。那么，Angular 在引导过程中，又是如何初始化根模块和入口组件的呢？</p> <h1 id="angular-的引导过程"><a href="#angular-的引导过程" class="header-anchor">#</a> Angular 的引导过程</h1> <p>前面我们说到，Angular 应用在浏览器中引导时，会创建浏览器平台，并引导根模块：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token function">platformBrowserDynamic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">bootstrapModule</span><span class="token punctuation">(</span>AppModule<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="引导根模块"><a href="#引导根模块" class="header-anchor">#</a> 引导根模块</h2> <h3 id="根模块-appmodule"><a href="#根模块-appmodule" class="header-anchor">#</a> 根模块 AppModule</h3> <p>在 Angular 中，每个应用有至少一个 Angular 模块，根模块就是你用来引导此应用的模块，它通常命名为 AppModule。</p> <p>当你使用 Angular CLI 命令 ng new 生成一个应用时，其默认的 AppModule 是这样的：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> BrowserModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/platform-browser'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> NgModule <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@angular/core'</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span> AppComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./app.component'</span><span class="token punctuation">;</span>

<span class="token decorator"><span class="token at operator">@</span><span class="token function">NgModule</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  declarations<span class="token operator">:</span> <span class="token punctuation">[</span>
    AppComponent
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  imports<span class="token operator">:</span> <span class="token punctuation">[</span>
    BrowserModule
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  providers<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  bootstrap<span class="token operator">:</span> <span class="token punctuation">[</span>AppComponent<span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AppModule</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
</code></pre></div><h3 id="引导根模块的过程"><a href="#引导根模块的过程" class="header-anchor">#</a> 引导根模块的过程</h3> <p>我们来看看平台层引导根模块的过程中都做了些什么：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token decorator"><span class="token at operator">@</span><span class="token function">Injectable</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">PlatformRef</span> <span class="token punctuation">{</span>
  <span class="token operator">...</span>

  <span class="token generic-function"><span class="token function">bootstrapModuleFactory</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">M</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>moduleFactory<span class="token operator">:</span> NgModuleFactory<span class="token operator">&lt;</span><span class="token constant">M</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> options<span class="token operator">?</span><span class="token operator">:</span> BootstrapOptions<span class="token punctuation">)</span><span class="token operator">:</span>
      <span class="token builtin">Promise</span><span class="token operator">&lt;</span>NgModuleRef<span class="token operator">&lt;</span><span class="token constant">M</span><span class="token operator">&gt;&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// 由于实例化模块时，会需要创建一些提供者，所以这里需要在实例化模块之前创建 NgZone</span>
    <span class="token comment">// 因此，这里创建了一个仅包含新 NgZone 的微型父注入器，并将其作为父传递给 NgModuleFactory</span>
    <span class="token keyword">const</span> ngZoneOption <span class="token operator">=</span> options <span class="token operator">?</span> options<span class="token punctuation">.</span>ngZone <span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> ngZoneEventCoalescing <span class="token operator">=</span> <span class="token punctuation">(</span>options <span class="token operator">&amp;&amp;</span> options<span class="token punctuation">.</span>ngZoneEventCoalescing<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> ngZoneRunCoalescing <span class="token operator">=</span> <span class="token punctuation">(</span>options <span class="token operator">&amp;&amp;</span> options<span class="token punctuation">.</span>ngZoneRunCoalescing<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> ngZone <span class="token operator">=</span> <span class="token function">getNgZone</span><span class="token punctuation">(</span>ngZoneOption<span class="token punctuation">,</span> <span class="token punctuation">{</span>ngZoneEventCoalescing<span class="token punctuation">,</span> ngZoneRunCoalescing<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> providers<span class="token operator">:</span> StaticProvider<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>provide<span class="token operator">:</span> NgZone<span class="token punctuation">,</span> useValue<span class="token operator">:</span> ngZone<span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token comment">// ApplicationRef 将在 Angular zone 之外创建</span>
    <span class="token keyword">return</span> ngZone<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token comment">// 在 ngZone.run 中创建 ngZoneInjector，以便在 Angular zone 中创建所有实例化的服务</span>
      <span class="token keyword">const</span> ngZoneInjector <span class="token operator">=</span> Injector<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>
          <span class="token punctuation">{</span>providers<span class="token operator">:</span> providers<span class="token punctuation">,</span> parent<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>injector<span class="token punctuation">,</span> name<span class="token operator">:</span> moduleFactory<span class="token punctuation">.</span>moduleType<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> moduleRef <span class="token operator">=</span> <span class="token operator">&lt;</span>InternalNgModuleRef<span class="token operator">&lt;</span><span class="token constant">M</span><span class="token operator">&gt;&gt;</span>moduleFactory<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>ngZoneInjector<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> exceptionHandler<span class="token operator">:</span> ErrorHandler<span class="token operator">|</span><span class="token keyword">null</span> <span class="token operator">=</span> moduleRef<span class="token punctuation">.</span>injector<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>ErrorHandler<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>exceptionHandler<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'No ErrorHandler. Is platform module (BrowserModule) included?'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token operator">...</span>
      <span class="token keyword">return</span> <span class="token function">_callAndReportToErrorHandler</span><span class="token punctuation">(</span>exceptionHandler<span class="token punctuation">,</span> ngZone<span class="token operator">!</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> initStatus<span class="token operator">:</span> ApplicationInitStatus <span class="token operator">=</span> moduleRef<span class="token punctuation">.</span>injector<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>ApplicationInitStatus<span class="token punctuation">)</span><span class="token punctuation">;</span>
        initStatus<span class="token punctuation">.</span><span class="token function">runInitializers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> initStatus<span class="token punctuation">.</span>donePromise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token operator">...</span>
          <span class="token comment">// 引导模块</span>
          <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_moduleDoBootstrap</span><span class="token punctuation">(</span>moduleRef<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token keyword">return</span> moduleRef<span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token generic-function"><span class="token function">bootstrapModule</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">M</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>
      moduleType<span class="token operator">:</span> Type<span class="token operator">&lt;</span><span class="token constant">M</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
      compilerOptions<span class="token operator">:</span> <span class="token punctuation">(</span>CompilerOptions<span class="token operator">&amp;</span>BootstrapOptions<span class="token punctuation">)</span><span class="token operator">|</span>
      <span class="token builtin">Array</span><span class="token operator">&lt;</span>CompilerOptions<span class="token operator">&amp;</span>BootstrapOptions<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator">&lt;</span>NgModuleRef<span class="token operator">&lt;</span><span class="token constant">M</span><span class="token operator">&gt;&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> options <span class="token operator">=</span> <span class="token function">optionsReducer</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> compilerOptions<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 编译并创建 @NgModule 的实例</span>
    <span class="token keyword">return</span> <span class="token function">compileNgModuleFactory</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>injector<span class="token punctuation">,</span> options<span class="token punctuation">,</span> moduleType<span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>moduleFactory <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">bootstrapModuleFactory</span><span class="token punctuation">(</span>moduleFactory<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">private</span> <span class="token function">_moduleDoBootstrap</span><span class="token punctuation">(</span>moduleRef<span class="token operator">:</span> InternalNgModuleRef<span class="token operator">&lt;</span><span class="token builtin">any</span><span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> appRef <span class="token operator">=</span> moduleRef<span class="token punctuation">.</span>injector<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>ApplicationRef<span class="token punctuation">)</span> <span class="token keyword">as</span> ApplicationRef<span class="token punctuation">;</span>
    <span class="token comment">// 引导应用程序</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>moduleRef<span class="token punctuation">.</span>_bootstrapComponents<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 在应用程序的根级别引导新组件</span>
      moduleRef<span class="token punctuation">.</span>_bootstrapComponents<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>f <span class="token operator">=&gt;</span> appRef<span class="token punctuation">.</span><span class="token function">bootstrap</span><span class="token punctuation">(</span>f<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>moduleRef<span class="token punctuation">.</span>instance<span class="token punctuation">.</span>ngDoBootstrap<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      moduleRef<span class="token punctuation">.</span>instance<span class="token punctuation">.</span><span class="token function">ngDoBootstrap</span><span class="token punctuation">(</span>appRef<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token operator">...</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>_modules<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>moduleRef<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>根模块引导时，除了编译并创建 AppModule 的实例，还会创建 NgZone，关于 NgZone 的请参考<a href=""></a>。在编译和创建 AppModule 的过程中，便会创建<code>ApplicationRef</code>，即 Angular 应用程序。</p> <h2 id="引导-angular-应用程序"><a href="#引导-angular-应用程序" class="header-anchor">#</a> 引导 Angular 应用程序</h2> <p>前面在引导根模块过程中，创建了 Angular 应用程序之后，便会在应用程序的根级别引导新组件：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token comment">// 在应用程序的根级别引导新组件</span>
moduleRef<span class="token punctuation">.</span>_bootstrapComponents<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>f <span class="token operator">=&gt;</span> appRef<span class="token punctuation">.</span><span class="token function">bootstrap</span><span class="token punctuation">(</span>f<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>我们来看看这个过程会发生什么。</p> <h3 id="应用程序-applicationref"><a href="#应用程序-applicationref" class="header-anchor">#</a> 应用程序 ApplicationRef</h3> <p>一个 Angular 应用程序，提供了以下的能力：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token decorator"><span class="token at operator">@</span><span class="token function">Injectable</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ApplicationRef</span> <span class="token punctuation">{</span>
  <span class="token comment">// 获取已注册到该应用程序的组件类型的列表</span>
  <span class="token keyword">public</span> <span class="token keyword">readonly</span> componentTypes<span class="token operator">:</span> Type<span class="token operator">&lt;</span><span class="token builtin">any</span><span class="token operator">&gt;</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token comment">// 获取已注册到该应用程序的组件的列表</span>
  <span class="token keyword">public</span> <span class="token keyword">readonly</span> components<span class="token operator">:</span> ComponentRef<span class="token operator">&lt;</span><span class="token builtin">any</span><span class="token operator">&gt;</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token comment">// 返回一个 Observable，指示应用程序何时稳定或不稳定</span>
  <span class="token comment">// 如果在应用程序引导时，引导任何种类的周期性异步任务，则该应用程序将永远不会稳定（例如轮询过程）</span>
  <span class="token keyword">public</span> <span class="token keyword">readonly</span> isStable<span class="token operator">!</span><span class="token operator">:</span> Observable<span class="token operator">&lt;</span><span class="token builtin">boolean</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>

  <span class="token function">constructor</span><span class="token punctuation">(</span>
      <span class="token keyword">private</span> _zone<span class="token operator">:</span> NgZone<span class="token punctuation">,</span> <span class="token keyword">private</span> _injector<span class="token operator">:</span> Injector<span class="token punctuation">,</span> <span class="token keyword">private</span> _exceptionHandler<span class="token operator">:</span> ErrorHandler<span class="token punctuation">,</span>
      <span class="token keyword">private</span> _componentFactoryResolver<span class="token operator">:</span> ComponentFactoryResolver<span class="token punctuation">,</span>
      <span class="token keyword">private</span> _initStatus<span class="token operator">:</span> ApplicationInitStatus<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 创建时，主要进行两件事：</span>
        <span class="token comment">// 1. 宏任务结束后，检测视图是否需要更新。</span>
        <span class="token comment">// 2. 在 Angular Zone 之外创建对 onStable 的预订，以便在 Angular Zone 之外运行回调。</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 在应用程序的根级别引导新组件</span>
  <span class="token generic-function"><span class="token function">bootstrap</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>componentOrFactory<span class="token operator">:</span> ComponentFactory<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span><span class="token operator">|</span>Type<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> rootSelectorOrNode<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token operator">|</span><span class="token builtin">any</span><span class="token punctuation">)</span><span class="token operator">:</span>
      ComponentRef<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token comment">// 调用此方法以显式处理更改检测及其副作用</span>
  <span class="token function">tick</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token comment">// 关联视图，以便对其进行脏检查，视图销毁后将自动分离</span>
  <span class="token function">attachView</span><span class="token punctuation">(</span>viewRef<span class="token operator">:</span> ViewRef<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token comment">// 再次从脏检查中分离视图</span>
  <span class="token function">detachView</span><span class="token punctuation">(</span>viewRef<span class="token operator">:</span> ViewRef<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>那么，我们来看看<code>bootstrap()</code>过程中，Angular 都做了些什么。</p> <h3 id="在应用程序的根级别引导根组件"><a href="#在应用程序的根级别引导根组件" class="header-anchor">#</a> 在应用程序的根级别引导根组件</h3> <p>将新的根组件引导到应用程序中时，Angular 将指定的应用程序组件安装到由<code>componentType</code>的选择器标识的 DOM 元素上，并引导自动更改检测以完成组件的初始化。</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token decorator"><span class="token at operator">@</span><span class="token function">Injectable</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ApplicationRef</span> <span class="token punctuation">{</span>
  <span class="token generic-function"><span class="token function">bootstrap</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>componentOrFactory<span class="token operator">:</span> ComponentFactory<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span><span class="token operator">|</span>Type<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> rootSelectorOrNode<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token operator">|</span><span class="token builtin">any</span><span class="token punctuation">)</span><span class="token operator">:</span>
      ComponentRef<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span>
    <span class="token comment">// 如果未与其他模块绑定，则创建与当前模块关联的工厂</span>
    <span class="token keyword">const</span> ngModule <span class="token operator">=</span>
        <span class="token function">isBoundToModule</span><span class="token punctuation">(</span>componentFactory<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token keyword">undefined</span> <span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_injector<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>NgModuleRef<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> selectorOrNode <span class="token operator">=</span> rootSelectorOrNode <span class="token operator">||</span> componentFactory<span class="token punctuation">.</span>selector<span class="token punctuation">;</span>
    <span class="token comment">// 创建组件</span>
    <span class="token keyword">const</span> compRef <span class="token operator">=</span> componentFactory<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>Injector<span class="token punctuation">.</span><span class="token constant">NULL</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> selectorOrNode<span class="token punctuation">,</span> ngModule<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> nativeElement <span class="token operator">=</span> compRef<span class="token punctuation">.</span>location<span class="token punctuation">.</span>nativeElement<span class="token punctuation">;</span>
    <span class="token comment">// 创建可测试服务挂钩</span>
    <span class="token keyword">const</span> testability <span class="token operator">=</span> compRef<span class="token punctuation">.</span>injector<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>Testability<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> testabilityRegistry <span class="token operator">=</span> testability <span class="token operator">&amp;&amp;</span> compRef<span class="token punctuation">.</span>injector<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>TestabilityRegistry<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>testability <span class="token operator">&amp;&amp;</span> testabilityRegistry<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      testabilityRegistry<span class="token punctuation">.</span><span class="token function">registerApplication</span><span class="token punctuation">(</span>nativeElement<span class="token punctuation">,</span> testability<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 组件销毁时，销毁关联视图以及相关的服务</span>
    compRef<span class="token punctuation">.</span><span class="token function">onDestroy</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">detachView</span><span class="token punctuation">(</span>compRef<span class="token punctuation">.</span>hostView<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">remove</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>components<span class="token punctuation">,</span> compRef<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>testabilityRegistry<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        testabilityRegistry<span class="token punctuation">.</span><span class="token function">unregisterApplication</span><span class="token punctuation">(</span>nativeElement<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 加载组件，包括关联视图、监听变更等</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_loadComponent</span><span class="token punctuation">(</span>compRef<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token operator">...</span>
    <span class="token keyword">return</span> compRef<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>在创建根组件的过程中，会关联 DOM 元素视图、添加对状态变更的检测机制。</p> <p>根组件是一个入口组件，Angular CLI 创建的默认应用只有一个组件<code>AppComponent</code>，Angular 会在引导过程中把它加载到 DOM 中。</p> <p>在根组件的创建过程中，通常会根据根组件中引用到的其他组件，触发一系列组件的创建并形成组件树。大多数应用只有一个组件树，并且只从一个根组件开始引导。</p> <h3 id="创建组件过程"><a href="#创建组件过程" class="header-anchor">#</a> 创建组件过程</h3> <p>Angular 中创建组件的过程如下（参考<a href="https://angular.cn/guide/architecture-services" target="_blank" rel="noopener noreferrer">服务与依赖注入简介<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>）：</p> <ol><li>当 Angular 创建组件类的新实例时，它会通过查看该组件类的构造函数，来决定该组件依赖哪些服务或其它依赖项。</li> <li>当 Angular 发现某个组件依赖某个服务时，它会首先检查是否该注入器中已经有了那个服务的任何现有实例。如果所请求的服务尚不存在，注入器就会使用以前注册的服务提供者来制作一个，并把它加入注入器中，然后把该服务返回给 Angular。</li> <li>当所有请求的服务已解析并返回时，Angular 可以用这些服务实例为参数，调用该组件的构造函数。</li></ol> <p>Angular 会在执行应用时创建注入器，第一个注入器是根注入器，创建于引导过程中。借助注入器继承机制，可以把全应用级的服务注入到这些组件中。</p> <p>到这里，Angular 分别完成了根模块、根组件和组件树的引导过程，通过编译器则可以将组件和视图渲染到页面上。</p> <h2 id="总结"><a href="#总结" class="header-anchor">#</a> 总结</h2> <p>在应用程序的引导过程中，Angular 采取了以下步骤来加载我们的第一个视图：</p> <ol><li>加载<code>index.html</code>。</li> <li>加载 Angular、第三方库和应用程序。</li> <li>加载应用程序入口点<code>Main.ts</code>。</li> <li>加载根模块。</li> <li>加载根组件。</li> <li>加载模板。</li></ol> <p>本文我们重点从根模块的引导过程开始，介绍了引导 Angular 应用程序、引导根组件、组件的创建等过程。至于组件树的创建和渲染，则可以参考<a href="">编译器</a>相关的内容。</p> <h3 id="参考"><a href="#参考" class="header-anchor">#</a> 参考</h3> <ul><li><a href="https://angular.cn/guide/bootstrapping" target="_blank" rel="noopener noreferrer">通过根模块启动应用<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://angular.cn/guide/entry-components" target="_blank" rel="noopener noreferrer">Angular-入口组件<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://www.tektutorialshub.com/angular/angular-bootstrapping-application/" target="_blank" rel="noopener noreferrer">Bootstrapping in Angular: How It Works Internally<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/front-end-playground/edit/sourcecode/docs/front-end-others/deep-into-angular/angular-design-di-3-bootstrap.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <!----> <blockquote>部分文章中使用了一些网站的截图，如果涉及侵权，请告诉我删一下谢谢~</blockquote> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本文版权归作者所有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。</div> <div>出处：被删的前端游乐场</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-2-hierarchical-di.html" class="prev">
          7.多级依赖注入设计
        </a></span> <span class="next"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-0-design.html">
          9.Ivy编译器整体设计
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-9022" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><span class="el-popover__reference-wrapper"><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty0.svg);"></div></span></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/front-end-playground/assets/js/app.1e2670bf.js" defer></script><script src="/front-end-playground/assets/js/2.38d016d1.js" defer></script><script src="/front-end-playground/assets/js/3.e3f029cb.js" defer></script><script src="/front-end-playground/assets/js/106.890f6d8d.js" defer></script>
  </body>
</html>
